﻿using Grpc.Core;
using Grpc.Core.Interceptors;


//Interceptor 【客户端】调用重写以下项：
//BlockingUnaryCall：截获一元 RPC 的阻塞调用。
//AsyncUnaryCall：截获一元 RPC 的异步调用。
//AsyncClientStreamingCall：截获客户端流式处理 RPC 的异步调用。
//AsyncServerStreamingCall：截获服务器流式处理 RPC 的异步调用。
//AsyncDuplexStreamingCall：截获双向流式处理 RPC 的异步调用。

//Interceptor 【服务器】响应侦听器，重写以下项：
//UnaryServerHandler：截获一元 RPC。
//ClientStreamingServerHandler：截获客户端流式处理 RPC。
//ServerStreamingServerHandler：截获服务器流式处理 RPC。
//DuplexStreamingServerHandler：截获双向流式处理 RPC
  public class ServerLoggerInterceptor : Interceptor
  {
      private readonly ILogger<ServerLoggerInterceptor> _logger;

      public ServerLoggerInterceptor(ILogger<ServerLoggerInterceptor> logger)
      {
          _logger = logger;
      }

      public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
          TRequest request,
          ServerCallContext context,
          UnaryServerMethod<TRequest, TResponse> continuation)
      {
          LogCall<TRequest, TResponse>(MethodType.Unary, context);

          try
          {
              return await continuation(request, context);
          }
          catch (Exception ex)
          {
              // Note: The gRPC framework also logs exceptions thrown by handlers to .NET Core logging.
              _logger.LogError(ex, $"Error thrown by {context.Method}.");

              throw;
          }
      }

      public override Task<TResponse> ClientStreamingServerHandler<TRequest, TResponse>(
          IAsyncStreamReader<TRequest> requestStream,
          ServerCallContext context,
          ClientStreamingServerMethod<TRequest, TResponse> continuation)
      {
          LogCall<TRequest, TResponse>(MethodType.ClientStreaming, context);
          return base.ClientStreamingServerHandler(requestStream, context, continuation);
      }

      public override Task ServerStreamingServerHandler<TRequest, TResponse>(
          TRequest request,
          IServerStreamWriter<TResponse> responseStream,
          ServerCallContext context,
          ServerStreamingServerMethod<TRequest, TResponse> continuation)
      {
          LogCall<TRequest, TResponse>(MethodType.ServerStreaming, context);
          return base.ServerStreamingServerHandler(request, responseStream, context, continuation);
      }

      public override Task DuplexStreamingServerHandler<TRequest, TResponse>(
          IAsyncStreamReader<TRequest> requestStream,
          IServerStreamWriter<TResponse> responseStream,
          ServerCallContext context,
          DuplexStreamingServerMethod<TRequest, TResponse> continuation)
      {
          LogCall<TRequest, TResponse>(MethodType.DuplexStreaming, context);
          return base.DuplexStreamingServerHandler(requestStream, responseStream, context, continuation);
      }

      private void LogCall<TRequest, TResponse>(MethodType methodType, ServerCallContext context)
          where TRequest : class
          where TResponse : class
      {
          _logger.LogWarning($"Starting call. Type: {methodType}. Request: {typeof(TRequest)}. Response: {typeof(TResponse)}");
          WriteMetadata(context.RequestHeaders, "caller-user");
          WriteMetadata(context.RequestHeaders, "caller-machine");
          WriteMetadata(context.RequestHeaders, "caller-os");

          void WriteMetadata(Metadata headers, string key)
          {
              var headerValue = headers.GetValue(key) ?? "(unknown)";
              _logger.LogWarning($"{key}: {headerValue}");
          }
      }
  }
